#include <Server.h>
#include <cstring>
#include <process.h>
#include <ctime>
#include <Windows.h>
#include <iostream>
#include <Threading.h>
using namespace std;

#define NUMBEROFCLIENTS 1

int main()
{ 
	/** Creating multiple objects **/
	WindowsThreading *Obj = new WindowsThreading[NUMBEROFCLIENTS];

	// Create Server object.
	Server ServerObj;

	// Create Server socket and set socket options.
	ServerObj.CreateSocket(TCPSOCKET);		// No argument means TCPSOCKET
	ServerObj.SetSocketOptions();

	// Initialise Server address struct and bind it with Server's socket.
	ServerObj.InitialiseAddress(6000);		// No argument here will take default port.
	ServerObj.Bind();

	// Listen for incoming connections.
	ServerObj.Listen();
	ServerObj.DisplayServerInfo();

	// Accept any incoming connections.
	ServerObj.Accept();
	ServerObj.DisplayClientInfo();

	//receive.
	int* recived_buffer;
	
	ServerObj.Receive();
	//int number_recieved;
	//number_recieved = ServerObj.GetNumOfBytesReceived()/4;
	//cout<<"Number of integers recieved:"<<number_recieved<<endl;
	cout << "No. of Bytes received: " << ServerObj.GetNumOfBytesReceived() << endl;
	char* buff=ServerObj.GetBuffer();
	recived_buffer = (int*)buff;
	/** setting the values **/
	Obj[0].SetNumberOfThreads(4);
	Obj[0].SetRowsMatrixA(recived_buffer[0]);
	Obj[0].SetColumsMatrixA(recived_buffer[1]);
	Obj[0].SetRowsMatrixB(recived_buffer[2]);
	Obj[0].SetColumsMatrixB(recived_buffer[3]);
	
	Obj[0].SetMatrixA( recived_buffer+4);
	Obj[0].SetMatrixB(recived_buffer + (Obj[0].GetRowsMatrixA())*(Obj[0].GetColumsMatrixA()) + 4);
	
	
	
	/** creating data structure for threading **/
	DataForThreadFunc *data_for_thread_func = new DataForThreadFunc[Obj[0].GetNumberOfThreads()]; //object=number of threads
	for(int i=0; i<Obj[0].GetNumberOfThreads(); i++)
	{
		data_for_thread_func[i].current_object = Obj;	//assigning same object address to all data structure
		data_for_thread_func[i].thread_number = 0;		//intializing
	}
	/** Dynamically Assigning memory **/
	Obj[0].AssignMemory(MATRIXC);
	Obj[0].AssignMemory(MATRIXBTRANSPOSE);

	
	time_t start_time, end_time, time_difference;
	cout<<"Start\n";

	/** creating dynamic thread array **/
	HANDLE* thread_array;
	thread_array = new HANDLE[Obj[0].GetNumberOfThreads()];
	
	/** starting threads **/
	start_time = clock();
	
	Obj[0].MatrixTranspose(); //B transpose
	
	for(int Thread_counter=0; Thread_counter<Obj[0].GetNumberOfThreads(); Thread_counter++)
	{	
		data_for_thread_func[Thread_counter].thread_number = Thread_counter;
		thread_array[Thread_counter] = (HANDLE)_beginthread(ThreadFunction,0,(void*)&data_for_thread_func[Thread_counter]);
	}
	for (int Thread_counter=0; Thread_counter<Obj[0].GetNumberOfThreads(); Thread_counter++)
		WaitForSingleObject(thread_array[Thread_counter], INFINITE);
	end_time = clock();
	time_difference = end_time - start_time;
	cout << "Time taken =  "<< time_difference <<"(msec)"<< endl;
	cout<<endl<<"Multiplication done"<<endl;
	
	/** Storing in files **/
	Obj[0].MatrixStore(MATRIXA);
	Obj[0].MatrixStore(MATRIXB);
	Obj[0].MatrixStore(MATRIXC);

	/** Sending**/
	//int temp;
	//buffer5 = matrix_C_Buffer
	int	matrixC_length=Obj[0].GetColumsMatrixB()* Obj[0].GetRowsMatrixA();
	unsigned char *matrix_C_Buffer= new unsigned char[sizeof(matrixC_length)*matrixC_length];
	ServerObj.memory_copy(matrix_C_Buffer, Obj[0].GetMatrixC(), sizeof(matrixC_length)*matrixC_length);
//	ServerObj.Send((void*)matrix_C_Buffer,sizeof(matrixC_length)*matrixC_length);
	//Sending Matrix C
	int count=0;
	matrixC_length*=4;
	while(1)
	{
		if (matrixC_length>50000)
		{
			ServerObj.Send((void*)(matrix_C_Buffer+count*50000),50000);//sending matrix
			matrixC_length-=50000;
			count++;
		}	
		else
		{
			matrixC_length/=4;
			ServerObj.Send((void*)(matrix_C_Buffer+count*50000),sizeof(int)*matrixC_length);//sending matrix
			break;
		}
	}

	// Close sockets.
	ServerObj.CloseClientSocket();
	ServerObj.CloseServerSocket();

	return 0;
}
